/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ru.jimbot.protocol;

import java.util.Timer;
import java.util.TimerTask;
import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ChatManagerListener;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.SASLAuthentication;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Presence.Mode;
import org.jivesoftware.smack.packet.Presence.Type;
import ru.jimbot.modules.AbstractProps;
import ru.jimbot.modules.MsgOutQueue;
import ru.jimbot.util.Log;
import ru.jimbot.util.MainProps;

/**
 * Класс работы с протоколом XMPP
 * @author Sergey
 * @author alex_xpert
 */
public class XMPPProtocol extends AbstractProtocol
implements MessageListener,ChatManagerListener,ConnectionListener {
    
    public AbstractProps  psp;

    public XMPPProtocol(AbstractProps props){
        psp = props;
        server_1 = MainProps.getStringProperty("jabber.serverDefault");
        port_1 = MainProps.getIntProperty("jabber.portDefault");
        mq = new MsgOutQueue(this, props.getIntProperty("bot.pauseOut"),
                props.getIntProperty("bot.pauseRestart"),
                props.getIntProperty("bot.msgOutLimit"));
    }

    @Override
    public void connect() {
        mq.start();
        doConnect();
    }

    @Override
    public void reConnect() {
        doDisconnect();
        doConnect();
    }

    @Override
    public void disconnect() {
        mq.stop();
        doDisconnect();
    }

    @Override
    public boolean isOnLine() {
        if(con_xmpp == null) return false;
        return connected;
    }

    @Override
    public void sendMsg(String to, String message) {
        try {
            Chat chat = con_xmpp.getChatManager().getThreadChat(to);
            if(chat==null)chat = con_xmpp.getChatManager().createChat(to,to, this);
            chat.sendMessage(message);
        } catch (XMPPException e) {
            e.printStackTrace();
        }
    }

    
    /**
     * Производит непосредственное подключение. Устанавливает нужные свойства.
     */
    private void doConnect() {
        try {
            ConnectionConfiguration config = new ConnectionConfiguration(server_1, port_1, server_1);
            SASLAuthentication.supportSASLMechanism("PLAIN");
            con_xmpp = new XMPPConnection(config);
            con_xmpp.connect();
            con_xmpp.login(screenName, password);
            con_xmpp.getChatManager().addChatListener(this);
            setStatus(true, psp.getStringProperty("icq.STATUS_MESSAGE2"));
            Log.info("Jabber JID " + (baseUin.contains("@") ? baseUin : baseUin + "@" + server_1) + " Online");
            connected = true;
        } catch (XMPPException ex) {
            ex.printStackTrace();
        }
    }
       
    private void doDisconnect() {
        Log.info("Jabber JID "+ (baseUin.contains("@") ? baseUin : baseUin + "@" + server_1) + " Offline");
        con_xmpp.disconnect();
        con_xmpp.getChatManager().removeChatListener(this);
        con_xmpp = null;
        Log.error("Разрыв соединения: " + baseUin);
        try {
            Log.info("Переподключение через 1 минуту...");
            Thread.sleep(60000);
            this.reConnect();
        } catch (Exception ex) {
            connected = false;
        }
    }
    
    @Override
    public void processMessage(Chat chat, Message msg) {
        if(msg.getType() == Message.Type.chat){
            String SenderID = chat.getParticipant().split("/")[0];
            String msg0 = msg.getBody();
            if(msg0==null) return;
            if(MainProps.isIgnor(SenderID)){
                Log.flood2("IGNORE LIST: " + SenderID + "->" + screenName + ": " + msg0);
                return;
            }
            protList.getMsg(SenderID, screenName, msg0,false);
        }
    }

    @Override
    public void chatCreated(Chat chat, boolean bln) {
        if (!bln){
            chat.addMessageListener(this);
        }
    }

    public void setStatus(boolean available, String status) {
        Presence.Type type = Type.available;
        Presence.Mode mode = Mode.chat;
        Presence presence = new Presence(type, status, 30, mode);
        con_xmpp.sendPacket(presence);
    }

    @Override
    public void RemoveContactList(String uin) {
    }

    @Override
    public void addContactList(String uin) {
    }

    @Override
    public void connectionClosed() {
        reconnectingIn(15);
    }

    @Override
    public void connectionClosedOnError(Exception e) {
        reconnectingIn(20);
    }

    @Override
    public void reconnectingIn(int seconds) {
        Timer tm = new Timer();
        TimerTask task = new TimerTask() {
    
            @Override
            public void run() {
                reConnect();
                cancel();
            }
            
        };
        
        tm.schedule(task, 1000 * seconds);
    }

    @Override
    public void reconnectionSuccessful() {
        connected=true;
    }

    @Override
    public void reconnectionFailed(Exception e) {
        reconnectingIn(20);
    }

    @Override
    public boolean isNoAuthUin(String uin){
        return psp.getBooleanProperty("chat.isAuthRequest");
    }

    @Override
    public AbstractProps getProps() {
        return psp;
    }

    @Override
    public void setStatus(int status) {
        Presence.Type type = Type.available;
        Presence.Mode mode = Mode.chat;
        String text = new String(psp.getStringProperty("icq.STATUS_MESSAGE2"));
        Presence presence = new Presence(type, text, 30, mode);
        con_xmpp.sendPacket(presence);
    }

    @Override
    public void getMsg(String sendSN, String recivSN, String msg, boolean isOffline) {
        protList.getMsg(sendSN, recivSN, msg, isOffline);
    }

    @Override
    public void getStatus(String sn, int status) {
        protList.getStatus(sn, status);
    }

    @Override
    public boolean userInfoRequest(String sn, String rsn) {
        lastInfo = sn;
        return true;
    }

    @Override
    public void authRequest(String uin, String msg) {}

    @Override
    public int getOuteqSize() {return this.mq.size();}
}
